package edu.ccut.saturn.component.impl.node;

/**
 * 工作流结点的实现类。
 * <p>继承了<code>AbstractNodeInfo</code>。<p>
 * 
 * @author 颜爽
 * @version 1.0 2008.8.18
 * 
 * @see <code>WorkFlowNodeInfo</code>
 */
import java.util.HashMap;
import java.util.List;

import edu.ccut.saturn.component.ComponentManager;
import edu.ccut.saturn.component.IComponent;
import edu.ccut.saturn.component.ILogicContext;
import edu.ccut.saturn.component.IParameterContext;
import edu.ccut.saturn.component.IParameterInfo;
import edu.ccut.saturn.component.SaturnComponentException;
import edu.ccut.saturn.component.impl.SaturnParameterContext;
import edu.ccut.saturn.component.loader.node.NodeInfoLoader;
import edu.ccut.saturn.component.loader.node.WorkFlowNodeInfoLoader;
import edu.ccut.saturn.component.utils.ExceptionUtils;
import edu.ccut.saturn.component.xml.ISaturnElement;
import edu.ccut.saturn.component.xml.SaturnElement;

public class WorkFlowNodeInfo extends AbstractNodeInfo {
	/*
	 * <workflow exception="" id="3" next="2" x="230" y="162">
	 * <key>edu.ccut.saturn.basecomponent::/databaseComponent/UpdateBySQLWithParamComponent.wf</key>
	 * <name>主项变更</name> <version>1.0.0</version> <transaction
	 * type="requireNew"></transaction> <parameters> <parameter id="1"
	 * name="sql" classType="java.lang.String" passingType="in">
	 * <value-key>'update czrk_jbxx set xm = '${xm}' where gmsfhm='${sfz}''</value-key>
	 * <scope>1</scope> <description>自定义sql</description> </parameter>
	 * <parameter id="2" name="result" classType="java.lang.Integer"
	 * passingType="out"> <value-key>result</value-key> <scope>1</scope>
	 * <description>sql执行所修改的记录条数</description> </parameter> <parameter id="3"
	 * name="context" classType="java.util.HashMap" passingType="in">
	 * <value-key>${context}</value-key> <scope>1</scope> <description></description>
	 * </parameter> </parameters> <description>依带参数的SQL更新组件</description>
	 * </workflow>
	 */
	private String key;

	private String version;

	private String type;

	private String exceptionId;

	public WorkFlowNodeInfo(String key, String id, String name,
			String description, String nextId, List<IParameterInfo> parameters,
			String version, String type, String exceptionId, String x, String y) {

		super(id, name, description, nextId, parameters, x, y, "workflow");

		this.version = version;
		this.key = key;
		this.type = type;
		this.exceptionId = exceptionId;
	}

	public String getVersion() {
		return version;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	protected IParameterContext createParamContext(ILogicContext logicContext,
			String type) {

		SaturnParameterContext parameterContext = new SaturnParameterContext(type);
		List<IParameterInfo> parameterInfos = getParameterInfos();
		HashMap<String, String> paramMap = new HashMap<String, String>();
		parameterContext.addParameter(key, String.class);
		parameterContext.addParameter(version, String.class);

		if (parameterInfos != null) {
			parameterInfos.get(0);

			for (int i = 0; i < parameterInfos.size(); i++) {
				IParameterInfo parameterInfo = parameterInfos.get(i);

				if (i < parameterInfos.size() - 1) {
					paramMap.put(parameterInfo.getName(), (String) logicContext
							.getValue(parameterInfo.getValueKey()));

				} else {
					// start parameter
					parameterContext.addParameter(paramMap, HashMap.class);
					// creator
					parameterContext.addParameter((String) logicContext
							.getValue(parameterInfo.getValueKey()),
							String.class);
				}
			}
		}
		parameterContext.setDatabaseBroker(logicContext.getDatabaseBroker());
		return parameterContext;
	}

	
	public IComponent getComponent(String key) throws SaturnComponentException {
		return ComponentManager.getInstance().getComponent(key);
	}	
	
	@Override
	public void doExecute(ILogicContext logicContext) throws Exception {
		// String wfExeCompKey =
		// "edu.ccut.saturn.workflow::/publicModule/component/WFAutoStart.component";
		String wfExeCompKey = "edu.ccut.saturn.workflow::/publicComponent/WFAutoStart.component";
		IParameterContext context = null;

		IComponent component;
		try {
			component = this.getComponent(wfExeCompKey);
		} catch (SaturnComponentException e) {
			logger.error("ERROR : { message : '" + ExceptionUtils.getExMessage(e) + "', process: '" + logicContext.getId() + "', node : '" + 
					this.getNodeType() + " " + this.getId() + " " + this.getName() + "'}");
			throw e;
		}
		
		try {
						
			context = createParamContext(logicContext, type);
			ComponentManager.beforeExecuteComponent(this, context);
			
			component.execute(context);

		} catch (Exception exception) {
			logger.error("ERROR : {message :'" + ExceptionUtils.getExMessage(exception) + "', process : '" + logicContext.getId() + "', node : '" +
					 super.getNodeType() + " " + super.getId() + " " + super.getName() + "'}");

			if (this.exceptionId != null && this.exceptionId.length() != 0) {
				
				logicContext.setNodeRouter(this.getId(), this.exceptionId);
				
				logger.debug("the next node to excute after the node ["
						+ this.getId() + "] change to node ["
						+ this.exceptionId + "] to handler the exception!");

			} else {
				throw exception;
			}

		} finally {
			ComponentManager.afterExecuteComponent(this, context);
		}
		// 没有参数输出需求，不需要刷新
		// logicContext
		// .refreshContextFromParameterContext(getParameterInfos(), context);

	}

	public String getKey() {
		return key;
	}

	@Override
	protected IParameterContext createParameterContext(
			ILogicContext logicContext) throws Exception {

		return null;
	}

	public ISaturnElement toSaturnElement() {
		ISaturnElement workFlowElement = new SaturnElement(
				WorkFlowNodeInfoLoader.KEY_NODETYPE_WORKFLOW);

		workFlowElement.addAttribute(NodeInfoLoader.KEY_NODE_ID, this.getId());
		workFlowElement.addAttribute(NodeInfoLoader.KEY_NODE_NEXT, this
				.getNextId());

		workFlowElement.addAttribute(NodeInfoLoader.KEY_NODE_X, this.getX());
		workFlowElement.addAttribute(NodeInfoLoader.KEY_NODE_Y, this.getY());
		workFlowElement.addAttribute(NodeInfoLoader.KEY_NODE_EXCEPTION,
				this.exceptionId);

		ISaturnElement keyElement = new SaturnElement(NodeInfoLoader.KEY_NODE_KEY,
				this.key);

		ISaturnElement nameElement = new SaturnElement(
				NodeInfoLoader.KEY_NODE_NAME, this.getName());

		ISaturnElement descriptionElement = new SaturnElement(
				NodeInfoLoader.KEY_NODE_DESCRIPTION, this.getDescription());

		ISaturnElement versionElement = new SaturnElement(
				WorkFlowNodeInfoLoader.KEY_WORKFLOW_VERSION, this.version);

		ISaturnElement transactionElement = new SaturnElement(
				WorkFlowNodeInfoLoader.KEY_NODE_START_TRANSACTION);

		transactionElement.addAttribute(
				WorkFlowNodeInfoLoader.KEY_LOGIC_TRANSACTION_TYPE, this.type);

		ISaturnElement parametersElement = new SaturnElement(
				NodeInfoLoader.KEY_PARAMETER_LIST);

		if (this.getParameterInfos() != null) {

			for (IParameterInfo parameterInfo : this.getParameterInfos()) {
				parametersElement.addSubElement(parameterInfo.toSaturnElement());
			}
		}
		workFlowElement.addSubElement(keyElement);
		workFlowElement.addSubElement(nameElement);
		workFlowElement.addSubElement(descriptionElement);
		workFlowElement.addSubElement(versionElement);
		workFlowElement.addSubElement(transactionElement);
		workFlowElement.addSubElement(parametersElement);
		return workFlowElement;
	}

}
